<?xml version="1.0" encoding="UTF-8"?><d:tdl xmlns="http://www.w3.org/1999/xhtml" xmlns:b="http://www.backbase.com/2006/btl" xmlns:bb="http://www.backbase.com/2006/client"  xmlns:d="http://www.backbase.com/2006/tdl" >

	<d:namespace name="http://www.backbase.com/2006/btl">

		<d:uses element="dataPagedObserver" src="../dataBinding/dataBinding.xml"/>
		<d:uses element="focusableElement" src="../focus/focus.xml"/>
		<d:uses element="positionElement dimensionElement" src="../visualElement/visualElement.xml"/>
		<d:uses element="labelImplementor" src="../label/label.xml"/>
		<d:uses behavior="resize" src="../resize/resize.xml"/>

		<d:element name="listGridBase" extends="b:dataPagedObserver b:positionElement b:dimensionElement b:focusableElement" abstract="true">
			

			

			

			

			

			<d:resource type="text/javascript"><![CDATA[if(!window.btl) window.btl = {};

if(!btl.listGrid) btl.listGrid = {};

//for editing
btl.listGrid.edit = { 'row' : null, 'index' : null, 'aQueries' : [], 'aControls' : [], 'aRowChildren' : []};

btl.listGrid.hasVScrollBar = function btl_listGrid_hasVScrollBar( oGrid){
	return oGrid.viewDataTableContainer.offsetWidth != oGrid.viewDataTableContainer.clientWidth;
}
//init fieldCreator, fieldUpdater, fieldDestroyer
btl.listGrid.initFProperties = function btl_listGrid_initFProperties( oGridCol){
	var aChildren = oGridCol.getProperty('childNodes');
	var aNames = ['fieldCreator', 'fieldUpdater', 'fieldDestroyer'];
	for(var i = 0, iLimit = aChildren.length; iLimit > i; i++)
		for(var j = 0, jMax = aNames.length; jMax > j; j++)
			if(aChildren[i] && bb.instanceOf(aChildren[i], btl.namespaceURI, aNames[j])){
				oGridCol.setProperty( aNames[j], aChildren[i]._._body);
				break;
			}
	if(!oGridCol._['_fieldCreator'])
		oGridCol._['_fieldCreator'] = function( viewNode, controller, recordId, value) {
			viewNode.innerHTML = value;
			return viewNode;
		};
	if(!oGridCol._['_fieldUpdater'])
		oGridCol._['_fieldUpdater'] = function( viewNode, controller, object, recordId, value) {
			viewNode.innerHTML = value;
			return viewNode;
		};
	if(!oGridCol._['_fieldDestroyer'])
		oGridCol._['_fieldDestroyer'] = function(){};
}

btl.listGrid.hasHScrollBar = function btl_listGrid_hasHScrollBar( oGrid){
	return oGrid.viewDataTableContainer.offsetHeight != oGrid.viewDataTableContainer.clientHeight;
}

btl.listGrid.handlemousedownLeaveEditMode = function btl_listGrid_handlemousedownLeaveEditMode( oEvent){
	var oGrid;
	var bOutsideEditRegion = true;
	var oRow = btl.listGrid.edit.row;
	if( oRow){
		oGrid = bb.getControllerFromView( oRow);

		// search upwards for btl.listGrid.editedRow and set bOutsideEditRegion to false if it's found
		var oElm = oEvent.viewTarget;
		while(bOutsideEditRegion && oElm){
			if(oElm == oRow) bOutsideEditRegion = false;
			oElm = oElm.parentNode;
		}

		// maybe the event happened on a dropdown  / popup that actually belongs to an editor - that would be ok
		var oElm =  oEvent.target;
		while(bOutsideEditRegion && oElm){
			if( bb.instanceOf(oElm, btl.namespaceURI, 'fieldEditor')) bOutsideEditRegion = false;
			oElm = oElm.getProperty('parentNode');
		}
	}
	if(bOutsideEditRegion){
		if(oGrid) {
			if (oGrid.leaveEditMode(true))
				bb.document.removeEventListener(oEvent.type, arguments.callee, true);
		} else {
			bb.document.removeEventListener(oEvent.type, arguments.callee, true);
		}
	}
}
//calls destroyers to remove custom objects
//oGrid 		 - grid to clean
// bClearContent - delete table rows
btl.listGrid.clear = function btl_listGrid_clear( oGrid, bClearContent){
	var oObjects = oGrid._.oRecords['cell_objects'];
	if( oObjects){ //clear it
		var aColumns = oGrid.getProperty('columns');
		var aQueries = [];
		var iQueryLength = aColumns.length;
		if(iQueryLength){
			for(var i = 0; i < iQueryLength; i++)
				aQueries[i] = aColumns[i].getProperty('fieldDestroyer');

			for(var sRecId in oObjects){
				if( !(oObjects[sRecId] instanceof Function))
					for(var i = 0, iMax = oObjects[sRecId].length; iMax > i; i++)
						if((i in oObjects[sRecId]) && (i in aQueries))
							aQueries[i].call( aColumns[i], oObjects[sRecId][i]);
					delete oObjects[sRecId];
				}
			if( bClearContent){
				var oRecords = oGrid.getProperty( 'localRecords');
				for( var recId in oRecords){
					var oRow = oRecords[ recId];
					delete oRecords[ recId];

					var oBody = oRow.parentNode;
					if( oBody) oBody.removeChild( oRow);
				}
				oGrid.setProperty('indexes', []);
			}
		}//if
	}
}

//default dataUpdate
btl.listGrid.dataUpdate = function btl_listGrid_dataUpdate(oGrid, action, records, actionObj) {
	if( oGrid._destructed) return; //destroyed
	if( action == "create"){
		oGrid.refresh();
		return;
	}

	var oSource = oGrid.getProperty('dataSource');
	var aIndexes = oGrid.getProperty('indexes');
	var aColumns = oGrid.getProperty('columns');
	var aFields = [];
	var iQueryLength = aColumns.length;

	for(var i = 0; i < iQueryLength; i++){
		var sQuery = aColumns[i].getProperty('select');
		var sAlign = aColumns[i].getProperty('align');
		var aFormats = btl.dataSource.getFormat( oSource, sQuery, aColumns[i].modelNode.getAttribute('format'));
		// add html escape formatter if datatype is not html
		if(aColumns[i].getProperty('dataType') != 'html')
			aFormats.unshift('htmlescape');
		aFields[i] = {
			'column'   :aColumns[i],
			'select'   :sQuery,
			'format'   :aFormats,
			'align'	   :sAlign,
			'width'    :(aColumns[i].getAttribute('width') || 'auto'),
			'hidden'   :aColumns[i].getProperty('hidden') ? true : false,
			'creator'  :aColumns[i].getProperty('fieldCreator'),
			'destroyer':aColumns[i].getProperty('fieldDestroyer'),
			'updater'  :aColumns[i].getProperty('fieldUpdater')
		}
		bb.html.addClass(aColumns[i].viewNode, 'btl-listGridCol-align-' + sAlign);
	}
	if( !oGrid._.oRecords) oGrid._.oRecords = {'rows':{}, 'cell_objects':{}}
	var oRecords = oGrid.getProperty( 'localRecords');
	var oObjects = oGrid._.oRecords.cell_objects;

	function deleteRecord( recordId){
		if( oObjects && oObjects[ recordId] && !(oObjects[ recordId] instanceof Function)){
			for(var iQuery = 0; iQueryLength > iQuery; iQuery++)
				if(iQuery in oObjects[ recordId])
					aFields[iQuery].destroyer.call( aColumns[ iQuery], oObjects[ recordId][iQuery]);
			delete oObjects[ recordId];
		}
		if(recordId in oRecords){
			var oRow = oRecords[ recordId];
			delete oRecords[ recordId];

			var oBody = oRow.parentNode;
			if( oBody) oBody.removeChild( oRow);
		}//if
	}
	var bUpdate = true, bSort = false, bSorted = false, bZebrafy = true;
	switch( action){
		case "sort":
				bUpdate = false; // dont update existing records
				bSort = true;
				bSorted = true;
		case "read":
			if( aIndexes.length){ //new records or new order
			// Don't use .nextSibling, .previousSibling because a record can occupy several rows
			// use only direct reference to the first row of a record and use insertBefore
				 var oRecordsNew = {}; //new set of local records with new order
				 var oRow = null;   // the first row out of order
				 var curInd = null; // its index
				 var iCur = -1;     // index offset
				 var aRecords2Update = []; //array of existing records to update if they are changed in the last 'read' action
				 var aNewOrder = [];
				 var ind = 0;

				if( bSort){//sort - change order (create new, reoder)
					//'records' contains new order
					aNewOrder = records;
					//find a row where record order is broken
					for(var i = 0; (aIndexes.length > i) && (records.length > i); i++){
						curInd = aIndexes[i];
						iCur = i;
						oRow = oRecords[ curInd];

						if( curInd != records[i]) break;
					}
					ind = i; //save the current position to start after
				} else {   //read - create new rows, insert in place or append at the end
					//if all records are new - append them at the end otherwise - 'records' contains new order
					var bAppend = true;
					for(var i = 0; records.length > i; i++){
						if( !(records[i] in oRecords))
							aNewOrder.push(records[i]);
						else {
							bSorted = true;
							aNewOrder = records;
							bAppend = false;
							break;
						}
					}
					if( bAppend){
						for(var j = aIndexes.length - 1; j >= 0; j--)
							if(!btl.dataSource.recordExists(oSource, aIndexes[j]))
								aIndexes.splice(j, 1);
						ind = aIndexes.length; //order is broken after it
						aNewOrder = aIndexes.concat( aNewOrder);
					} else { //find the place
						//find a row where record order is broken
						for(var i = 0; (aIndexes.length > i) && (records.length > i); i++){
							curInd = aIndexes[i];
							iCur = i;
							oRow = oRecords[ curInd];
							if( curInd != records[i]) break;
						}
						ind = i; //save the current position to start after
					}
				}
					//clear records which should not exist in the new 'indexes'
					var oDontRemove = {};
					for(var j = aNewOrder.length - 1; j >= 0; j--)
							oDontRemove[ aNewOrder[j]] = true;

					for(var recId in oRecords)
						if( !(oRecords[recId] instanceof Function)){
							if( oDontRemove[ recId] ){
								oRecordsNew[ recId] = oRecords[recId];
								aRecords2Update.push( recId);
							} else {
								deleteRecord( recId);
							}
						}
					if( (ind >= aIndexes.length) || !(curInd in oDontRemove)){ // all rows are in order
						curInd = null;
						iCur = -1;
						oRow = null;
					}
				oGrid.setProperty( 'localRecords', oRecordsNew); //save the reference it's need for fieldCreators
					var oBody = oGrid.viewDataTableContainer.firstChild.tBodies[0];
					if(!oRow) oRow = null;
				for(; aNewOrder.length > ind; ind++){
						 var sRecId = aNewOrder[ind];
						 var oNewRow;
					if( sRecId == curInd){ //this row is already in place
						do{ //find next old row out of order
							iCur++;
							curInd = iCur < aIndexes.length ? aIndexes[ iCur] : null;
						}while( curInd in oRecordsNew);

						oRow = curInd && oRecords[ curInd] ? oRecords[ curInd] : null;
						} else if( sRecId in oRecords){ // move corresponding row to a new place
							oBody.insertBefore( oRecords[sRecId], oRow);
							oNewRow = oRow;
						} else { //create new row
						oNewRow = document.createElement('tr');
						oNewRow.setAttribute( "rowid", sRecId);
						oBody.insertBefore( oNewRow, oRow);
						oRecordsNew[ sRecId] = oNewRow;

				 		var oEvent = bb.document.createEvent('Events');
						oEvent.initEvent('rowCreated', false, false);
						oEvent.recordId = sRecId;
						oGrid.dispatchEvent(oEvent);

						var oNewCell;
						for(var iQuery = 0; iQuery < iQueryLength; iQuery++){
							oNewCell = document.createElement('td');
							oNewCell.className = "btl-grid-cell";
							oNewCell.style.textAlign = aFields[iQuery].align;
							if( aFields[iQuery].hidden) oNewCell.style.display = 'none';
							oNewCell.innerHTML = '<div class="btl-grid-cell-content"></div>';
							oNewRow.appendChild( oNewCell);
						}

						var oViewGate = oGrid.viewGate;
						oObjects[ sRecId] = [];
						for(var iQuery = 0; iQuery < iQueryLength; iQuery++){ //aColumns[iQuery]
							oGrid.viewGate = oNewRow.cells[iQuery].firstChild;
							//fieldCreator
							oObjects[ sRecId][iQuery] = aFields[iQuery].creator.call(aColumns[iQuery],
								oGrid.viewGate, oGrid, sRecId,
								btl.dataSource.getValue(oSource, sRecId, aFields[iQuery].select, aFields[iQuery].format));
						}
						oGrid.viewGate = oViewGate;
					}
				 }//for
				if( bUpdate){ //update existing records
					var oViewGate = oGrid.viewGate;
					for(var i = 0, iMax = aRecords2Update.length; iMax > i; i++){
						var sRecId = aRecords2Update[i];
						if( (sRecId in oRecords) && btl.dataSource.recordChanged(oSource, sRecId)){ //update values
							var aCells = oRecords[ sRecId].cells;
							for(var j = 0, jMax = aFields.length; jMax > j; j++){
								oGrid.viewGate = aCells[j].firstChild;
								//call updater
								var obj = oObjects[ sRecId][j];
								obj = aFields[j].updater.call( aColumns[j], oGrid.viewGate, oGrid, obj, sRecId,
									btl.dataSource.getValue(oSource, sRecId, aFields[j].select, aFields[j].format));
								if ( obj) oObjects[ sRecId][j] = obj;
							}
						}
					}//for
					oGrid.viewGate = oViewGate;
					if( bb.browser.gecko){//FF workaround: bug 9647
						var old = oBody.style.paddingBottom;
						oBody.style.paddingBottom = '1px';
						setTimeout( function(){ oBody.style.paddingBottom = old}, 10)
					}
				}
				oGrid.setProperty('indexes', aNewOrder);
				oGrid.setProperty('sorted', bSorted);
			} else { //full update - (re)build the table
				if( oObjects){ //clear it
					for(var sRecId in oObjects)
						if( !(oObjects[sRecId] instanceof Function))
							deleteRecord( sRecId);
				}
				if( records.length){ //if there are records to rebuild the table
					// Initialize variables.
					var aHtml = [];
					var aIndexes = [];

					// Show or hide column filler.
					var bHideFiller = false;
					for(var i = 0, iLimit = aFields.length; iLimit > i; i++)
						if(!aFields[i].hidden && (aFields[i].width == 'auto')){
							bHideFiller = true;
							break;
						}
					if(bHideFiller) bb.html.addClass(oGrid.viewNode, 'btl-grid-columnFillers-hidden');
					else bb.html.removeClass(oGrid.viewNode, 'btl-grid-columnFillers-hidden');

					// Open table, open, fill and close table head, open table body.
					aHtml[ aHtml.length] = '<table cellpadding="0" cellspacing="0" border="0">';
					var aClasses = oGrid.aColClasses || [];
					var iClassLength = aClasses.length;

					var sColgroup = "<colgroup>";
					for(var iQuery = 0; iQueryLength > iQuery; iQuery++){
						var sClass = "";
						if(iClassLength) {
							sClass = ' class="' + aClasses[iQuery % iClassLength] + '"';
						}
						sColgroup += '<col' + sClass + ' /> '
					}
					sColgroup += "</colgroup>";

					if( !bb.browser.ie) aHtml[ aHtml.length] = sColgroup;

					aHtml[ aHtml.length] = '<thead><tr class="btl-grid-clean">';
					for(var iQuery = 0; iQueryLength > iQuery; iQuery++){
						aHtml[ aHtml.length] = '<th class="btl-grid-clean" style="';
						if(aFields[ iQuery].hidden) aHtml[ aHtml.length] = 'display:none;';
						aHtml[ aHtml.length] = 'width:' + bb.string.escapeXml(aFields[ iQuery].width) + ';" ></th>'; //DO NOT SHORTCLOSE THIS BREAKS IE!
					}
					var iNumRows = records.length + 1;
					aHtml[ aHtml.length] = '<th class="btl-grid-clean columnFiller" rowspan="'+ iNumRows+'"></th><th class="btl-grid-clean scrollbarFiller" style="width:';
					aHtml[ aHtml.length] = bb.html.getScrollBarWidth();
					aHtml[ aHtml.length] = 'px" rowspan="'+iNumRows+'"></th></tr></thead>';

					if( bb.browser.ie) aHtml[ aHtml.length] = sColgroup;//sometimes IE converts 'thead' into 'tbody'

					aHtml[ aHtml.length] = '<tbody>';

					// Fill table body, close table body, close table.
					var aClasses = oGrid.aRowClasses || [];
					var iClassLength = aClasses.length;
					for(var iRow = 0, iMax = records.length; iMax > iRow; iRow++){
						aHtml[aHtml.length] = '<tr';
						if(iClassLength){
							aHtml[aHtml.length] = ' class="' + aClasses[iRow % iClassLength] + '"';
						}
						aHtml[aHtml.length] = ' rowid="' + bb.string.escapeXml(String(records[iRow])) + '">';

						for(var iQuery = 0; iQuery < iQueryLength; iQuery++){
							aHtml[ aHtml.length] = '<td class="btl-grid-cell" style="text-align:' + bb.string.escapeXml(aFields[iQuery].align);
							if( aFields[iQuery].hidden) aHtml[ aHtml.length] = '; display:none';
							aHtml[ aHtml.length] = ';"><div class="btl-grid-cell-content"></div></td>';
						}
						aHtml[ aHtml.length] = '</tr>';
					}
					aHtml[ aHtml.length] = '</tbody></table>';

					// Render table.
					var oContainer = oGrid.viewDataTableContainer;
					oContainer.innerHTML = aHtml.join('');

					var oRecords = {}; //assosiated array recordId - a table row
					oGrid.setProperty( 'localRecords', oRecords);

					oObjects = {}; //assosiated array recordId - array of developer created cell objects(see b:fieldCreator, b:fieldDestroyer, b:fieldUpdater)
					var oBody = oContainer.firstChild.tBodies[ 0];

					if(oBody){
						oBody.pageNumber = oGrid.getProperty('page');
						var oViewGate = oGrid.viewGate;
						var aRows = []; //collect rows for they can be modified
						if( bb.browser.ie && oBody.rows.length) //fix for IE f@#(
							oBody.rows[0].setAttribute('rowid', records[0]);

						for(var i = 0, iMax = oBody.rows.length; iMax > i; i++){
							var sRecId = records[i];
							aRows[i] = oBody.rows[i];
							oRecords[ sRecId] = aRows[i];

					 		var oEvent = bb.document.createEvent('Events');
							oEvent.initEvent('rowCreated', false, false);
							oEvent.recordId = sRecId;
							oGrid.dispatchEvent(oEvent);
						}

						for(var i = 0, iMax = aRows.length; iMax > i; i++){//we've made a row for every index
							var oRow = aRows[i];
							var sRecId = records[i];
							oObjects[ sRecId] = [];
							aIndexes[ i] = sRecId;

							for(var iQuery = 0; iQuery < iQueryLength; iQuery++){ //aColumns[iQuery]
								oGrid.viewGate = oRow.cells[ iQuery].firstChild;
								//fieldCreator
								oObjects[ sRecId][iQuery] = aFields[iQuery].creator.call(aColumns[iQuery],
									oGrid.viewGate, oGrid, sRecId,
									btl.dataSource.getValue(oSource, sRecId, aFields[iQuery].select, aFields[iQuery].format));

							}
							oGrid.viewGate = oViewGate;
						}
					}
					oGrid.setProperty("indexes", aIndexes);
					oGrid._.oRecords['cell_objects'] = oObjects;
					var iTotalPages = oGrid.getProperty('totalPages');
					var iPage = oGrid.getProperty('page');
					if( iPage > iTotalPages) oGrid.setAttribute('page', 1);
				} else {
					oGrid.setProperty("indexes", []);
					oGrid._.oRecords['cell_objects'] = {};
					oGrid.setProperty("page", 0);
				}
				oGrid.setProperty('sorted', true); //it sets if it is sortable
				// Align the column headers and the data table visually.
				oGrid.alignColumns();
			}
			break;
		case "delete":
			var oDeleted = {};
			for(var i = 0; records.length > i; i++){
				var sRecId = records[i];
				deleteRecord( sRecId);
				oDeleted[sRecId] = true;
			}//for
			//update 'indexes'
			for(var i = aIndexes.length - 1; i >= 0; i--)
				if( aIndexes[i] in oDeleted)
						aIndexes.splice(i, 1);

			//update 'selectedIndexes'
			var aSelIndexes = oGrid.getProperty('selectedIndexes');
			oGrid.setAttribute('selectedIndexes', aSelIndexes.join(','));

			var iNPages = oGrid.getProperty('totalPages');
			var iCurPage = oGrid.getProperty('page');
			if(iNPages && iCurPage > iNPages) {
				setTimeout( function(){ oGrid.goTo(oGrid.getProperty('totalPages'))}, 10); // load the last page
			}
			else if(oSource.getProperty('totalRecords') > aIndexes.length) {
				setTimeout( function(){ oGrid.refresh( true)}, 10); // reload page
			}
			break;
		case "update":
			var oViewGate = oGrid.viewGate;
			for(var i = 0, iMax = records.length; iMax > i; i++){
				var sRecId = records[i];
				if( sRecId in oRecords){ //update values
					var aCells = oRecords[ sRecId].cells;
					for(var j = 0, jMax = aFields.length; jMax > j; j++){
						oGrid.viewGate = aCells[j].firstChild;
						//call updater
						var obj = oObjects[ sRecId][j];
						obj = aFields[j].updater.call( aColumns[j], oGrid.viewGate, oGrid, obj, sRecId,
							btl.dataSource.getValue(oSource, sRecId, aFields[j].select, aFields[j].format));
						if ( obj) oObjects[ sRecId][j] = obj;
					}
				}
			}//for
			oGrid.viewGate = oViewGate;
			bZebrafy = false;
			break;
		default:
			break;
	}
	if(bZebrafy) oGrid.zebrafy();

	// Save and display sort state on the columns.
	oGrid.setColumnSortState(oGrid.getProperty('sortIndex'), oGrid.getProperty('sortDirection'));

	// Refresh the selection
	oGrid.refreshSelection();

	// Fire the pageRefreshed event.
	bb.command.fireEvent(oGrid, 'pageRefreshed', false, false);

};

/**
 * Handler for onactivate event to focus the invisible input inside
 * the listGrid if any of it's view elements is clicked. If the event
 * happend not for some child controller the handler does not take any actions.
 * @param {controller object} oGrid grid to handle event in.
 * @param {XMLEvent} oEvent event object.
 */
btl.listGrid._handleActivation = function(oGrid, oEvent) {
	var oFocusEl = oGrid.getProperty('focusElement');
	if ((bb.getControllerFromView(oEvent.srcElement) == oGrid) && (!oFocusEl.disabled)) {
		oFocusEl.focus();
	}
};

/**
 * Handler for onbeforedeactivate event of the invisible input inside
 * the listGrid, to cancel the loose of the focus if the listGridCol
 * or fieldEditor were activated.
 * @param {controller object} oGrid grid to handle event in.
 * @param {XMLEvent} oEvent event object.
 * @return false if we need to cancel deactivation, otherwise true.
 */
btl.listGrid._handleDeactivation = function(oGrid, oEvent) {
	if(oGrid._._preventDeactivation){
		return false;
	}
	return true;
};
]]></d:resource>

			<d:attribute name="renderMode">
				
			</d:attribute>

			<d:attribute name="columnResizing" default="true">
				
				<d:changer type="text/javascript"><![CDATA[
					this.setColumnResizing(value);
				]]></d:changer>
			</d:attribute>

			<d:attribute name="readonly" default="false">
				
			</d:attribute>

			<d:attribute name="rowClasses">
				
				<d:mapper type="text/javascript"><![CDATA[
					var aRes = value.split(',');
					for(var i = 0; i < aRes.length; i++)
						aRes[i] = aRes[i].replace(/^\s*|\s*$/g, '');
					this.aRowClasses = aRes;
				]]></d:mapper>
			</d:attribute>

			<d:attribute name="columnClasses">
				
				<d:mapper type="text/javascript"><![CDATA[
					var aRes = value.split(',');
					for(var i = 0; i < aRes.length; i++)
						aRes[i] = aRes[i].replace(/^\s*|\s*$/g, '');
					this.aColClasses = aRes;
				]]></d:mapper>
			</d:attribute>

			<d:attribute name="selectedIndexes">
				
				<d:changer type="text/javascript"><![CDATA[
					this.refreshSelection();
				]]></d:changer>
			</d:attribute>

			<d:attribute name="selectMultiple" default="true">
				
				<d:changer type="text/javascript"><![CDATA[
					this._._selectMultiple = value;
					this.setAttribute('selectedIndexes', this.getProperty('selectedIndexes').join(','));
				]]></d:changer>
			</d:attribute>

			<d:attribute name="showColumnHeaders">
				
				<d:mapper type="text/javascript"><![CDATA[
					if(value == 'false')
						bb.html.addClass(this.viewNode, 'btl-grid-columnHeaders-hidden');
					else {
						bb.html.removeClass(this.viewNode, 'btl-grid-columnHeaders-hidden');
						this.alignColumns();
					}
				]]></d:mapper>
			</d:attribute>

			<d:attribute name="sortable" default="true">
				
				<d:changer type="text/javascript"><![CDATA[
					// Update sortable property
					this.setProperty(name, btl.isTrueValue(name, value));
				]]></d:changer>
				<d:mapper type="text/javascript"><![CDATA[
					// Visualize sort state
					if(value == 'true') bb.html.addClass(this.viewNode, 'btl-grid-sortable');
					else bb.html.removeClass(this.viewNode, 'btl-grid-sortable');
				]]></d:mapper>
			</d:attribute>

			<d:property name="editControls">
				
				<d:getter type="text/javascript"><![CDATA[
					/*
						- if column is editable
							- if it has an editor, use it
							- else get its data type and generate an editor based on the data type
					*/
					var aControls = this._['_editControls'];
					if(!aControls){
						aControls = [];
						var aColumns = this.getProperty('columns');
						var oControl;
						var sType;
						var oEditor;
						for(var i = 0, iLimit = aColumns.length; i < iLimit; i++){
							if(aColumns[i].getAttribute('readonly') != 'true'){
								//find a fieldEditor
								var arr = aColumns[i].getProperty('childNodes');
								for ( var j = 0; j < arr.length; j++)
									if (arr[j] && bb.instanceOf(arr[j], btl.namespaceURI, 'fieldEditor')) {
										oEditor = arr[j];
										break;
									}

								if ( !oEditor) {//create default
									oEditor = aColumns[i].appendChild( btl.fieldEditor.createDefaultEditor(aColumns[i].getProperty("dataType").toLowerCase()));
								}
								aControls[aControls.length] = oEditor ? oEditor : null;
							}
							else
								aControls[aControls.length] = null;
							oEditor = null;
						}//for
						this._['_editControls'] = aControls;
					}
					return aControls;
				]]></d:getter>
			</d:property>

			<d:property name="localRecords">
				
				<d:getter type="text/javascript"><![CDATA[
					if( !this._.oRecords) this._.oRecords = { 'rows' : {}};
					return this._.oRecords.rows;
				]]></d:getter>
				<d:setter type="text/javascript"><![CDATA[
					if( !this._.oRecords) this._.oRecords = {} ;
					this._.oRecords['rows'] = value;
				]]></d:setter>
			</d:property>

			<d:property name="focusedRow">
				
				<d:setter type="text/javascript"><![CDATA[
					// Remove focus class from old row, store value, add focus class to new row and scroll it into view.
					var sOldRow = this._['_focusedRow'];
					if( sOldRow && sOldRow != value){
						var oRow = this._.oRecords.rows[ sOldRow];
						if( oRow) this.setRowFocusedState( oRow, false);
					}
					this._['_focusedRow'] = value;
					if( value && value != sOldRow){
						var oRow = this._.oRecords.rows[ value];
						if( oRow){
							this.setRowFocusedState( oRow, true);

							// Check if the container is scrolled down enough and fix if necessary.
							var oContainer = oRow.parentNode.parentNode.parentNode;
							var iScrollBarAdjustment = btl.listGrid.hasHScrollBar(this) ? bb.html.getScrollBarWidth() : 0;
							var iDifference = oRow.offsetTop + oRow.offsetHeight + iScrollBarAdjustment - oContainer.offsetHeight - oContainer.scrollTop;
							if(iDifference > 0) oContainer.scrollTop += iDifference;

							// Check if the container is scrolled up enough and fix if necessary.
							iDifference = oContainer.scrollTop - oRow.offsetTop;
							if(iDifference > 0) oContainer.scrollTop -= iDifference;
						}
					}
				]]></d:setter>
			</d:property>

			<d:property name="mode">
				
				<d:getter type="text/javascript"><![CDATA[
					var sValue = this._['_' + name];
					return sValue ? sValue : 'view';
				]]></d:getter>
			</d:property>

			<d:property name="columns">
				
				<d:getter type="text/javascript"><![CDATA[
					var aChildren = this.getProperty('childNodes');
					var aColumns = [];
					for(var i = 0, iLimit = aChildren.length; i < iLimit; i++){
						if(aChildren[i] && bb.instanceOf(aChildren[i], btl.namespaceURI, 'listGridColBase'))
							aColumns[aColumns.length] = aChildren[i];
					}
					return aColumns;
				]]></d:getter>
			</d:property>

			<d:property name="rowClasses">
				
				<d:getter type="text/javascript"><![CDATA[
					return this.aRowClasses || [];
				]]></d:getter>
			</d:property>

			<d:property name="selectedIndex">
				
			</d:property>

			<d:property name="selectedIndexes">
				
				<d:getter type="text/javascript"><![CDATA[
					// Takes string value of selectedIndexes attribute and:
					// - removes indexes that don't exist in data set
					// - if multiple selection is disabled, all but the first index are discarded
					var sIndexes = this.getAttribute('selectedIndexes') || '';
					var aIndexesRough = sIndexes.split(/\s|;|,/);
					var aIndexes = [];

					var oRecords = this.getProperty('localRecords');
					var bSingle = !btl.isTrueValue('selectMultiple', this.getAttribute('selectMultiple'));
					for(var i = 0, iLimit = aIndexesRough.length; iLimit > i; i++)
						if( aIndexesRough[i].length){
							aIndexes.push(aIndexesRough[i]);
							if( bSingle) return aIndexes;
						}
					return aIndexes;
				]]></d:getter>
			</d:property>

			<d:property name="selectedRows">
				
				<d:getter type="text/javascript"><![CDATA[
					return this._['_selectedRows'] ? this._['_selectedRows'] : {};
				]]></d:getter>
			</d:property>

			<d:property name="shiftAnchorIndex">
				
			</d:property>

			<d:property name="sortIndex">
				
				<d:getter type="text/javascript"><![CDATA[
					var iIndex = -1;
					var sSortValue = this.getProperty('sortField');
					var aColumns = this.getProperty('columns');
					for(var i = 0, iLimit = aColumns.length; iLimit > i; i++){
						if(aColumns[i]._.select == sSortValue){
							iIndex = i;
							break;
						}
					}
					return iIndex;
				]]></d:getter>
			</d:property>

			<d:property name="suppressedEditRow">
				
			</d:property>

			<d:property name="viewColumnFiller">
				
			</d:property>

			<d:method name="alignColumns">
				
				<d:body type="text/javascript"><![CDATA[

					var oGrid = this;
					var oDataContainer = this.viewDataTableContainer;
					var oColumnContainer = this.viewColumnDiv;
					var oScrollBarButton = this.viewScrollBarButton;

					if(!oDataContainer || oDataContainer.offsetWidth < 1)
						return;

					if(!oDataContainer.firstChild){
						 bb.html.addClass(oGrid.viewNode, 'btl-grid-columnFillers-hidden'); //hide extra column
						 return;
					}

					var iScrollBarWidth = bb.html.getScrollBarWidth();
					var bScrollBar = btl.listGrid.hasVScrollBar( oGrid);
					var aHeadColumns = oGrid.getProperty('columns');
					var aBodyColumns = oDataContainer.firstChild.tHead.rows[0].cells;
					var sWidth;

					// show or hide scrollbar filler
					aBodyColumns[aBodyColumns.length - 1].style.width = iScrollBarWidth + 'px';
					if(bScrollBar) bb.html.addClass(oGrid.viewNode, 'btl-grid-scrollbarFillers-hidden');
					else bb.html.removeClass(oGrid.viewNode, 'btl-grid-scrollbarFillers-hidden');

					//set proper filler rowspan attribute
					var sNumRows = '' + (oDataContainer.firstChild.tBodies[0].rows.length + 1);
					aBodyColumns[aBodyColumns.length - 1].setAttribute('rowspan', sNumRows);
					aBodyColumns[aBodyColumns.length - 2].setAttribute('rowspan', sNumRows);

					// show or hide column filler
					var bHideFiller = false;
					for(var i = 0, iLimit = aHeadColumns.length; !bHideFiller && (i < iLimit); i++){
						if(!aHeadColumns[i].getProperty('hidden')){
							sWidth = aHeadColumns[i].getAttribute('width');
							if(!sWidth || sWidth == 'auto') bHideFiller = true;
						}
					}
					if(bHideFiller) bb.html.addClass(oGrid.viewNode, 'btl-grid-columnFillers-hidden');
					else bb.html.removeClass(oGrid.viewNode, 'btl-grid-columnFillers-hidden');

					// set width of data columns
					var totalWidth = 0
					if( oGrid.getAttribute( 'showColumnHeaders') != 'false')
						for(var i = 0, iLimit = aHeadColumns.length; i < iLimit; i++){
							sWidth = bb.html.getBoxObject(aHeadColumns[i].viewNode).width;
							totalWidth += sWidth;
							aBodyColumns[i].style.width = sWidth + 'px';
						}
					if(bb.browser.gecko) {
							if (bHideFiller){// workaround for bug 10129
								var delta = oGrid.viewNode.offsetWidth - oScrollBarButton.offsetWidth - totalWidth;
								if(delta) {
									var i = aHeadColumns.length-1;
									aHeadColumns[i].viewNode.style.width = aBodyColumns[i].style.width = (parseInt(aBodyColumns[i].style.width) + delta) + "px";
								}
							}
							if (bb.browser.version == 1.9){//FF3 issue - workaround for bug 11768
								var oBody = oDataContainer.firstChild.tBodies[oDataContainer.firstChild.tBodies.length - 1];
								if (oBody.rows.length > 1){
									if(!('btldrawfix' in oBody))
										oBody.btldrawfix = oBody.style.paddingBottom;
									oBody.style.paddingBottom = oBody.style.paddingBottom == '1px' ? '' : '1px';
									setTimeout(function(){oBody.style.paddingBottom = oBody.btldrawfix}, 10);
								}
							}
					}
					// trigger proper reflow in Internet Explorer
					if (bb.browser.ie){
						/* addClass + removeClass force repaint. The class is fake. */
						bb.html.addClass(aHeadColumns[0].viewNode, 'reflow-please');
						bb.html.removeClass(aHeadColumns[0].viewNode, 'reflow-please');
						var oBody = oDataContainer.firstChild.tBodies[oDataContainer.firstChild.tBodies.length - 1];
						if (oBody.rows.length > 1) {
							oBody.moveRow(0, 1);
							oBody.moveRow(0, 1);
						}
					}

				]]></d:body>
			</d:method>

			<d:method name="createColumnMenu">
				
				<d:body type="text/javascript"><![CDATA[
					/*
					var aColumns = this.getProperty('columns');
					var oMenu = bb.document.createElementNS(btl.namespaceURI, 'contextMenu');
					var oPopup = bb.document.createElementNS(btl.namespaceURI, 'menuPopUp');
					oMenu.appendChild(oPopup);
					var oItem;
					for(var i = 0, iLimit = aColumns.length; i < iLimit; i++){
						oItem = bb.document.createElementNS(btl.namespaceURI, 'menuItem');
						oItem.setAttribute('type',  'checkbox');
						oItem.setAttribute('selected',  'true');
						oItem.setAttribute('label',  'foo');
						oPopup.appendChild(oItem);
					}
					this.appendChild(oMenu);
					this._oMenu = oMenu;*/
					bb.command.create(new DOMParser().parseFromString('foo', 'text/xml'), bb.document.getProperty('documentElement'));
				]]></d:body>
			</d:method>

			<d:method name="commandOnRow">
				
				<d:argument name="row"/>
				<d:argument name="ctrlkey"/>
				<d:argument name="shiftkey"/>
				<d:body type="text/javascript"><![CDATA[
					// put arguments in more readable variables
					var bCtrlKey = ctrlkey;
					var bShiftKey = shiftkey;

					// the old and new selection
					var aOldIndexes = this.getProperty('selectedIndexes');
					var aNewIndexes = [];
					var sNewIndex = row.getAttribute('rowid');

					// if multiple selection is disabled, pretend that ctrl and shift are not used
					if(this.getAttribute('selectMultiple') == 'false'){
						bCtrlKey = false;
						bShiftKey = false;
					}

					// left click
					if(!bCtrlKey && !bShiftKey){
						// if the row is not yet selected, the new selection is just the clicked row
						aNewIndexes[0] = sNewIndex;
					}

					// left click with ctrl
					else if(bCtrlKey && !bShiftKey){
						// new selection includes new row only if it wasn't in the old selection
						var bAddNewIndex = true;
						for(var i = 0, iLimit = aOldIndexes.length; i < iLimit; i++){
							if(aOldIndexes[i] != sNewIndex) aNewIndexes[aNewIndexes.length] = aOldIndexes[i];
							else bAddNewIndex = false;
						}
						if(bAddNewIndex) aNewIndexes[aNewIndexes.length] = sNewIndex;
					}

					// left click with shift
					else if(!bCtrlKey && bShiftKey){
						// new selection is everything from last non-shift click to new click
						var sOldIndex = this.getProperty('shiftAnchorIndex');
						if(!sOldIndex) sOldIndex = this.getProperty('focusedRow');

						var iBothIndexes = 0;
						var aIndexes = this.getProperty('indexes');
						for(var i=0, iMax = aIndexes.length; iMax > i; i++){
							var sId = aIndexes[i];
							if( sId == sOldIndex || sId == sNewIndex)
								iBothIndexes += sOldIndex == sNewIndex ? 2 : 1;

							if( iBothIndexes == 1 || iBothIndexes == 2)
								aNewIndexes[aNewIndexes.length] = sId;

							if( iBothIndexes == 2) break;
						}
					}
					else if(bCtrlKey && bShiftKey){
						// new selection is everything from last non-shift click to new click
						var sOldIndex = this.getProperty('shiftAnchorIndex');
						if(!sOldIndex) sOldIndex = this.getProperty('focusedRow');

						var oOldIndexes = this.getProperty("selectedRows");
						var iBothIndexes = 0;
						var aIndexes = this.getProperty('indexes');
						for(var i=0, iMax = aIndexes.length; iMax > i; i++){
							var sId = aIndexes[i];
							if( sId == sOldIndex || sId == sNewIndex)
								iBothIndexes += sOldIndex == sNewIndex ? 2 : 1;

							if( sId in oOldIndexes || iBothIndexes == 1 || iBothIndexes == 2)
								aNewIndexes[aNewIndexes.length] = sId;

							if( iBothIndexes == 2) iBothIndexes++;
						}
					}

					// store focusedRow, shiftAnchorIndex and the new selection
					this.setProperty('focusedRow', sNewIndex);
					if(!bShiftKey || (bShiftKey && bCtrlKey)) this.setProperty('shiftAnchorIndex', sNewIndex);
					var sOldIndexes = this.getAttribute('selectedIndexes');
					var sNewIndexes = aNewIndexes.join(',');
					this.setAttribute('selectedIndexes', sNewIndexes);
					if(sNewIndexes != sOldIndexes){
				 		var oEvent = bb.document.createEvent('Events');
						oEvent.initEvent('selectionChanged', false, false);
						oEvent.recordId = sNewIndex;
						this.dispatchEvent(oEvent);

					}
				]]></d:body>
			</d:method>

			<d:method name="deleteSelectedRows">
				
				<d:body type="text/javascript"><![CDATA[
					var oSource = this.getProperty('dataSource');
					var aIndexes = this.getProperty('selectedIndexes');
					if( oSource && aIndexes.length){
						btl.dataSource.actionRequest(this, 'delete', aIndexes, true);
						this.setAttribute('selectedIndexes', '');
					}
				]]></d:body>
			</d:method>

			<d:method name="initEditMode">
				
				<d:argument name="focusedCellIndex"/>
				<d:body type="text/javascript"><![CDATA[
					// Only go into edit mode if the grid isn't read only, and if it is not in edit mode yet
					if(!btl.isTrueValue('readonly', this.getAttribute('readonly')) && this.getProperty('mode') != 'edit'){

						// Edited row becomes selection, fire selectionChanged, temporarily remove visualization of selection and focus
						var sRowId = this.getProperty('focusedRow');
						if( sRowId === null) return; //can't edit not focused row (it's possible for extra rows)
						this.setProperty('mode', 'edit');
						var sOldIndexes = this.getAttribute('selectedIndexes');
						var oRow = this._.oRecords.rows[ sRowId];

						this.setAttribute('selectedIndexes', sRowId);
						if(sRowId != sOldIndexes)	bb.command.fireEvent(this, 'selectionChanged', false, false);

						var oEdit = {};
						oEdit.row = oRow;
						oEdit.index = sRowId;

						this.setRowSelectedState(oRow, false);
						this.setRowFocusedState(oRow, false);

						// Enable text selection
						bb.html.enableUserSelect(this.viewNode);

						// Place edit controls in the cells of the edited row and set their values
						var aCells = oRow.cells;
						var aControls = this.getProperty('editControls');
						var aColumns = this.getProperty('columns');
						var oSource = this.getProperty('dataSource');
						oEdit.aOldValues = []; //to store old values
						oEdit.aControls = [];
						oEdit.aRowChildren = [];
						oEdit.aQueries = [];
						oEdit.aIsCheckBox = [];

						var bSuccess = true;

						for(var i = 0, iLimit = aControls.length; iLimit > i; i++){
							if(aColumns[i].getAttribute('readonly') != 'true' && !aColumns[i].getProperty('hidden')){

								var sQuery = aColumns[i]._.select;
								var editFormat = aColumns[i].modelNode.getAttribute('editFormat');
								if( editFormat && editFormat.length){ //there is attribute
									editFormat = btl.dataSource.getFormat( oSource, sQuery, editFormat);
									if( editFormat.length == 0 ) // formatter is not found
										editFormat = false;
								}
								else editFormat = false;
								//works with fieldEditor
								value = btl.dataSource.getValue(oSource, sRowId, sQuery, editFormat);
								oEdit.aQueries[i] = sQuery;
								oEdit.aControls[i] = aControls[i];
								oEdit.aOldValues[i] = value;
								oEdit.aRowChildren[i] = aCells[i].removeChild( aCells[i].firstChild);
								bb.html.addClass(aCells[i], 'btl-grid-cell-edit');
								if (aControls[i]) {
									aCells[i].insertBefore( aControls[i].viewNode, aCells[i].firstChild);
									if (!aControls[i].editStart(value, i === focusedCellIndex)) {//prevented
										bSuccess = false;
										break; //out of the loop
									}
								}
							}//if
						}//for
						btl.listGrid.edit = oEdit;
						if (bSuccess) {
							bb.document.addEventListener('mousedown', btl.listGrid.handlemousedownLeaveEditMode, true);

							// NOTE: this reflow is required here cause initially all the editors are invisible and
							// some of them (like slider for example) will not initialize properly without reflow
							// which would happen initially if the control was visible
							bb.ui.reflow(this);
						} else {//if prevented - then roll back edit starting
							this.leaveEditMode(false);
						}
					}
				]]></d:body>
			</d:method>

			<d:method name="leaveEditMode">
				
				<d:argument name="save"/>
				<d:body type="text/javascript"><![CDATA[
					var oSource = this.getProperty('dataSource');
					var oEdit = btl.listGrid.edit;
					var oRow = oEdit.row;
					var sRowId = oEdit.index;
					var aCells = oRow.cells;
					var bValueChanged = false;

					// loop over column to grab edit controls of columns that are editable and visible
					for(var i = 0, iLimit = oEdit.aControls.length; iLimit > i; i++){
						var oControl = oEdit.aControls[i];
						if( oControl && !oControl.editFinish()) {//prevented
							for( i--;i >= 0; i--)//show again
								if( oEdit.aControls[i])
									oEdit.aControls[i].editStart();
							return false;
						}
					}
					// the grid should take the focus before the focused editor is removed
					this.focus();

					// loop over column to grab edit controls of columns that are editable and visible
					for(var i = 0, iLimit = oEdit.aControls.length; iLimit > i; i++){
						var oControl = oEdit.aControls[i];
						if( oControl){
							if(save){
								sNewValue = oControl.getProperty('value');
								if( sNewValue != oEdit.aOldValues[i]){
									bValueChanged = true;
									btl.dataSource.setValue(oSource, sRowId, oEdit.aQueries[i], sNewValue);
								}
							}
							bb.html.removeClass(aCells[i], 'btl-grid-cell-edit');
							oControl.getProperty('parentNode').viewGate.appendChild(oControl.viewNode);
							aCells[i].appendChild( oEdit.aRowChildren[i]);
						}
					}

					// Disable text selection
					bb.html.disableUserSelect(this.viewNode);

					// Cleanup of display and return to view state.
					this.setRowSelectedState(oRow, true);
					this.setRowFocusedState(oRow, true);
					btl.listGrid.edit = {'row' : null, 'aControls' : []};
					this.setProperty('mode', 'view');

					// Reflect changed data in the view and fire edit event.
					if(save && bValueChanged){
						btl.dataSource.actionRequest( this, 'update', [sRowId]);
						var oEvent = bb.document.createEvent("Event");
						oEvent.initEvent('valueChanged', false, false);
						oEvent.recordId = sRowId;
						this.dispatchEvent(oEvent);
					}
					return true;
				]]></d:body>
			</d:method>

			<d:method name="refreshSelection">
				
				<d:body type="text/javascript"><![CDATA[
					// Highlights rows on current page
					var aIndexes = this.getProperty('selectedIndexes');
					var oRecords = this.getProperty('localRecords');
					var aSelectedRows = [];
					var oSelectedRows = {};

					for(var i = 0, iLimit = aIndexes.length; iLimit > i; i++){
						if( aIndexes[i] in oRecords){
							aSelectedRows[ aSelectedRows.length] = oRecords[ aIndexes[i]];
							oSelectedRows[ aIndexes[i]] = oRecords[ aIndexes[i]];
						}
					}

					var oOldRows = this.getProperty('selectedRows');

					// add highlights to new selection
					for(var sId in oSelectedRows)
						this.setRowSelectedState(oSelectedRows[sId], true);

					// remove highlights from old selection
					for(var sId in oOldRows)
						if( !(sId in oSelectedRows))
							this.setRowSelectedState(oOldRows[sId], false);

					this.setProperty('selectedIndex', aIndexes[0]);
					this.setProperty('selectedRows', oSelectedRows);
				]]></d:body>
			</d:method>

			<d:method name="reset">
				
				<d:body type="text/javascript"><![CDATA[
					this.setProperty('focusedRow', -1);

					// Deselect all rows
					this.setAttribute('selectedIndexes', '');

					// Go back to page 1
					this.setAttribute( 'page', 1);

					// Call refresh to trigger loading and rendering of new data
					this.sort( '', 'ascending');
				]]></d:body>
			</d:method>

			<d:method name="setColumnResizing">
				
				<d:argument name="allowResize"/>
				<d:body type="text/javascript"><![CDATA[
					var aColumns = this.getProperty('columns');
					if(allowResize == 'true'){
						var bFoundFirst = false;
						for(var i = 0, iLimit = aColumns.length; i < iLimit; i++){
							if(!bFoundFirst && !aColumns[i].getProperty('hidden')){
								bFoundFirst = true;
								aColumns[i].setAttribute('resizeEdges', 'right');
							}
							else aColumns[i].setAttribute('resizeEdges', 'right left');
							aColumns[i].setAttribute('resizeType', 'abstract');
							aColumns[i].setAttribute('resizeGripSize', '8px');
							aColumns[i].setProperty('resizable', true);
						}
					}
					else{
						for(var i = 0, iLimit = aColumns.length; i < iLimit; i++){
							aColumns[i].setProperty('resizable', false);
						}
					}
				]]></d:body>
			</d:method>

			<d:method name="setScrollPosition">
				
				<d:argument name="scrollx"/>
				<d:argument name="scrolly"/>
				<d:body type="text/javascript"><![CDATA[
					this.viewColumnDiv.scrollLeft = scrollx;
					var oEvent = bb.document.createEvent('UIEvents');
					oEvent.initUIEvent('scroll', true, false, null, null);
					this.dispatchEvent(oEvent);
				]]></d:body>
			</d:method>

			<d:method name="sortColumn">
				
				<d:argument name="column">
					
				</d:argument>
				<d:argument name="sortreverse">
					
				</d:argument>
				<d:body type="text/javascript"><![CDATA[
					if( this.getAttribute('sortable') == 'true'){

						var aColumns = this.getProperty('columns');
						if(aColumns[column]){
							var iSortAscending = this.getProperty('sortDirection') == 'ascending' ? 1 : 0;
							var iSortReverse = sortreverse ? 1 : 0;

							// Set sort state on the state object
							this.sort( aColumns[column]._.select, iSortReverse ^ iSortAscending ? 'ascending' : 'descending');
						}
					}
				]]></d:body>
			</d:method>

			<d:method name="zebrafy">
				
				<d:body type="text/javascript"><![CDATA[
					if(this.aRowClasses && this.aRowClasses.length && this.viewDataTableContainer && this.viewDataTableContainer.firstChild){
						var aBodies = this.viewDataTableContainer.firstChild.tBodies;
						var aRows = aBodies[aBodies.length - 1].rows;
						var iClass = 0;
						var iTotalClasses = this.aRowClasses.length;

						for(var i = 0, iMax = aRows.length; i < iMax; i++){
							if(!bb.html.hasClass(aRows[i], 'btl-grid-row-hidden')){
								var sClass = this.aRowClasses[iClass % iTotalClasses];
								if(!bb.html.hasClass(aRows[i], sClass)){
									bb.html.replaceClass(aRows[i], this.aRowClasses, sClass);
								}
								iClass++;
							}
						}
					}
				]]></d:body>
			</d:method>

			<d:method name="dataUpdate">
				<d:argument name="action"/>
				<d:argument name="records"/>
				<d:argument name="actionObj"/>
				<d:body type="text/javascript"><![CDATA[
					btl.listGrid.dataUpdate(this, action, records, actionObj);
				]]></d:body>
			</d:method>

			<d:method name="setColumnSortState">
				
				<d:argument name="column">
					
				</d:argument>
				<d:argument name="direction">
					
				</d:argument>
				<d:body type="text/javascript"><![CDATA[
					if(direction == undefined) direction = 'ascending';
					var aColumns = this.getProperty('columns');
					var bSorted = this.getProperty('sorted');
					for(var i = 0, iLimit = aColumns.length; i < iLimit; i++){
						if(bSorted && i == column){
							if(direction == 'ascending')
								bb.html.replaceClass(aColumns[i].viewNode, ['btl-grid-column-header-sorted-descending'], ['btl-grid-column-header-sorted-ascending']);
							else
								bb.html.replaceClass(aColumns[i].viewNode, ['btl-grid-column-header-sorted-ascending'], ['btl-grid-column-header-sorted-descending']);
						}
						else
							bb.html.removeClass(aColumns[i].viewNode, ['btl-grid-column-header-sorted-descending', 'btl-grid-column-header-sorted-ascending']);
					}
				]]></d:body>
			</d:method>

			<d:method name="clear">
				
				<d:body type="text/javascript"><![CDATA[
					this.setAttribute('selectedIndexes', '');
					btl.listGrid.clear( this, true);
				]]></d:body>
			</d:method>

			<d:constructor type="text/javascript"><![CDATA[
				// Store references to important elements.
				if( !this._.oRecords) this._.oRecords = { 'rows' : {}, 'cell_objects' : {}};
				// flag for preventing deactivation of the grid elements
				// it is used to workaround problems with focus in IE
				// where clicking on any element removes the focus from the
				// element that is currently focused, and if it is not
				// the listGrid view (listGridCol, etc.) the whole controller looses focus
				this._._preventDeactivation = false;
				//force loading fieldEditor API
				bb.command.destroy( bb.document.createElementNS(btl.namespaceURI, 'fieldEditor'));
			]]></d:constructor>

			<d:destructor type="text/javascript"><![CDATA[
				this._destructed = true;
				var ds = this.getProperty( 'dataSource');
				if( ds) if(ds._) ds.removeObserver( this);
				btl.listGrid.clear( this);
			]]></d:destructor>

			<d:handler event="construct" type="text/javascript"><![CDATA[
				bb.ui.reflow.add(this);
			]]></d:handler>

			<d:handler event="DOMNodeInsertedIntoDocument" type="text/javascript"><![CDATA[
				var oGrid = this;
				// event handler that enables the deactivation of the invisible input element
				var fEnableDeactivation = function() {
					oGrid._._preventDeactivation = false;
				};
				// event handler that disables the deactivation of the invisible input element
				var fDisableDeactivation = function(oEvent) {
					var oTarget = oEvent.target;
					if (bb.instanceOf(oTarget, btl.namespaceURI, "listGridColBase") ||
						bb.instanceOf(oTarget, btl.namespaceURI, "fieldEditor")) {
							oGrid._._preventDeactivation = true;
					}
				};
				// IE needs to prevent deactivation of the input if someone clicks inside the grid
				// (not true for the editor inside grid)
				if (bb.browser.ie) {
					this.addEventListener('mouseup', fEnableDeactivation, false);
					this.addEventListener('mouseleave', fEnableDeactivation, false);
					this.addEventListener('mousedown', fDisableDeactivation, false);
				}

				var aChildren = this.viewNode.childNodes;
				var oChild;
				for(var i = 0, iLimit = aChildren.length; i < iLimit; i++){
					oChild = aChildren[i];
					if (oChild.nodeType == 1) {
						if (oChild.className.match('btl-grid-dataViewContainer')) {
							this.viewDataTableContainer = oChild;
						}
						else if (oChild.className.match('btl-grid-head')) {
							this.viewColumnDiv = oChild;
						}
						else if (oChild.className.match('btl-grid-topRightFiller')) {
							this.viewScrollBarButton = oChild;
						}
					}
				}

				// Make some space on the right of the column headers for the menu button.
				var iScrollBarWidth = bb.html.getScrollBarWidth();
				this.viewColumnDiv.style.left = '-' + iScrollBarWidth + 'px';
				this.viewColumnDiv.style.paddingLeft = iScrollBarWidth + 'px';
				this.viewScrollBarButton.style.width = iScrollBarWidth + 'px';

				// If not all space is used by the columns, a filler should take it.
				this.createColumnFiller();

				// Disable text selection
				bb.html.disableUserSelect(this.viewNode);

				// Initiate column resizing and register for reflow events.
				this.setColumnResizing(this.getAttribute('columnResizing'));

			]]></d:handler>

			<d:handler event="focus" type="text/javascript"><![CDATA[
				// Setting focusedRow to its own value ensures that at least the default row is focused.
				this.setProperty('focusedRow', this.getProperty('focusedRow'));
				bb.html.replaceClass(this.viewNode, 'btl-grid-blurred', 'btl-grid-focused');
			]]></d:handler>

			<d:handler event="blur" type="text/javascript"><![CDATA[
				bb.html.replaceClass(this.viewNode, 'btl-grid-focused', 'btl-grid-blurred');
			]]></d:handler>

			<d:handler event="keydown" type="text/javascript"><![CDATA[
				/*
					In view mode when focused row is not selected:
						- Enter is a command on the row, modified by Ctrl and Shift
						- Space is a command on the row, modified by Ctrl and Shift
						- F2 selects the row and initiates edit mode
						- Up, Down, PageUp and PageDown move the focus

					In view mode when focused row is selected:
						- Enter initiates edit mode
						- Space initiates edit mode
						- F2 initiates edit mode
						- Up, Down, PageUp and PageDown move the focus

					In edit mode:
						- Escape discards changes and leaves edit mode
						- Enter confirms changes and leaves edit mode
						- Tab and Shift + Tab navigates the edit controls
				*/

				var sMode = this.getProperty('mode');
				var oRow = this._.oRecords.rows[ this.getProperty('focusedRow')];
				var bSelected = oRow && oRow.className.match('selected') ? true : false;
				var sKey = event.keyIdentifier;
				var bCtrl = navigator.platform.indexOf('Mac') != -1 ? event.metaKey || event.ctrlKey : event.ctrlKey;

				if(sMode == 'view' && oRow){
					// focus navigation keys
					if(sKey == 'Up' || sKey == 'Down' || sKey == 'PageUp' || sKey == 'PageDown' || sKey == 'Home' || sKey == 'End'){

						// prevent default browser actions from happening
						event.stopPropagation();
						event.preventDefault();

						// lovely variables... lekker lekker
						var oOldRow = oRow;
						var oBody = oOldRow.parentNode;
						var oNewRow;
						var iChange;
						var iDirection = 1;
						var iNewIndex;

						// determine new focused row
						iNewIndex = oOldRow.sectionRowIndex;
						if(sKey == 'Up') iChange = -1;
						else if(sKey == 'Down') iChange = 1;
						else if(sKey == 'PageUp') iChange = -10;
						else if(sKey == 'PageDown') iChange = 10;
						else if(sKey == 'Home') iChange = -iNewIndex;
						else if(sKey == 'End') iChange = oBody.rows.length;

						iNewIndex += iChange;
						if(iNewIndex < 0) iNewIndex = 0;
						else if(iNewIndex >= oBody.rows.length) iNewIndex = oBody.rows.length - 1;
						oNewRow = oBody.rows[iNewIndex];

						// If new row is hidden, pick next visible row in the same direction.
						// If new row is hidden and it's the last row in that direction, pick next visible row in opposite direction.
						if(iChange < 0) iDirection = -1;
						while(bb.html.hasClass(oNewRow, 'btl-grid-row-hidden')){
							oNewRow = oBody.rows[iNewIndex += iDirection];
							if(!oNewRow){
								iDirection = -iDirection;
								oNewRow = oBody.rows[iNewIndex += iDirection];
							}
						}
						// if multiple selection is disabled, pretend that modifier keys are not used
						if(this.getAttribute('selectMultiple') == 'false'){
							event.ctrlKey = false;
							event.shiftKey = false;
							event.metaKey = false;
							bCtrl = false;
						}
						if( bCtrl && !event.shiftKey){ // no selection change - focus only
							var sId = oNewRow.getAttribute('rowid');
							this.setProperty('focusedRow', sId);
							this.setProperty('shiftAnchorIndex', sId);
						} else
							this.commandOnRow(oNewRow, bCtrl, event.shiftKey);
					}

					// view mode, pressing delete deletes all selected rows
					else if(sKey == 'U+002E'){
						if(this.getAttribute('readonly') == 'false'){
							if(!bb.command.fireEvent(this, 'deleteSelection', false, true).defaultPrevented){
								event.preventDefault();
								this.deleteSelectedRows();
							}
						}
					}

					// view mode, focused row is not selected
					else if(!bSelected){
						// Enter or Space fires a command on the row
						if(sKey == 'Enter' || sKey == 'U+0020')
							this.commandOnRow(oRow, bCtrl, event.shiftKey);

						// F2 selects the row and initiates edit mode
						else if(sKey == 'F2'){
							this.commandOnRow(oRow, true, false);
							this.initEditMode();
						}
					}

					// view mode, focused row is selected
					else if(bSelected){
						// Space toggles selection of focused row if Ctrl is used, otherwise just adds it
						if(sKey == 'U+0020')
							this.commandOnRow(oRow, bCtrl, event.shiftKey);

						// Enter and F2 initiate edit mode
						else if(sKey == 'Enter' || sKey == 'F2')
							this.initEditMode();
					}
				}

				// edit mode
				else if(sMode == 'edit'){
					// Escape discards changes and leaves edit mode
					if(sKey == 'U+001B'){
						if( this.leaveEditMode(false))
							event.preventDefault();
					}

					// Enter confirms changes and leaves edit mode
					else if(sKey == 'Enter'){
						if( this.leaveEditMode(true))
							event.preventDefault();
					}
				}
			]]></d:handler>

			<d:handler event="mousedown" type="text/javascript"><![CDATA[
				/*
					1st mousedown: issue selection command on row
					2nd mousedown (double click!): initiate edit mode
				*/

				// Focus the grid
				if(event.target == this){
					event.preventDefault();
					var refocused = this != bb.activeElement;

					var iScrollX = btl.getScrollLeft(this.viewNode);
					var iScrollY = btl.getScrollTop(this.viewNode);
					var aCoordinates = bb.html.getBoxObject(this.viewNode);
					var iNewX = event.clientX + iScrollX - aCoordinates[0] + 1;
					var iNewY= event.clientY + iScrollY - aCoordinates[1] + 1;
					var oFocusElement = this.getProperty('focusElement');
					oFocusElement.style.left = iNewX + 'px';
		 			oFocusElement.style.top = iNewY + 'px';

					this.focus();
				}

				if(event.button == 0){
					/*
						Used to contain btl.containsElement(this.viewDataTableContainer, event.target.viewNode).
						event.target.viewNode has been changed to event.viewTarget in order to fix/work around
						bug 6822. Removing btl.containsElement entirely would probably cause issues when the
						content of the listGrid is parsed by the engine (JSF only).
					*/
					if((event.target == this) || btl.containsElement(this.viewDataTableContainer, event.viewTarget)){
						// Get reference to new row
						var oNewRow = null;
						var oElm = event.viewTarget;
						var oCell = null;
						var oLimit = this.viewNode;
						while(oElm && oElm != oLimit){
							if(oElm.tagName && oElm.tagName.toLowerCase() == 'td')
								oCell = oElm;//top cell is found

							else if(oElm.tagName && oElm.tagName.toLowerCase() == 'tr'){
								oNewRow = oElm;
								//bug 6854 do not break; here since editors may contain tr's and only an actual row of the grid should be set.
							}
							oElm = oElm.parentNode;
						}
						if(oNewRow && btl.containsElement(this.viewDataTableContainer, oNewRow)){
							if(oNewRow != btl.listGrid.edit.row){
								if(event.detail == 1){
									if(!oNewRow.className.match('selected') || refocused) this.setProperty('suppressedEditRow', oNewRow);
									else this.setProperty('suppressedEditRow', null);

									var bCtrl = event.ctrlKey;
									if(navigator.platform.indexOf('Mac') != -1 && !bb.browser.opera)
										bCtrl = event.metaKey;
									this.commandOnRow(oNewRow, bCtrl, event.shiftKey);
								}
								else if(event.detail == 2)
									this.initEditMode( oCell ? oCell.cellIndex : -1);
							}
						}
					}
				}
			]]></d:handler>

			<d:handler event="click" type="text/javascript"><![CDATA[
				/*
					click on column menu button: show the menu
					click on a selected row that was not selected by the mousedown of this click: initiate edit mode
				*/
				if(!event.defaultPrevented && event.button == 0){

					var sTargetName = event.target.getProperty('localName');
					if(sTargetName == this.getProperty('localName')){
						// get reference to new row
						var oRow = null;
						var oCell = null;
						var oElm = event.viewTarget;
						var oLimit = this.viewNode;
						while(oElm && oElm != oLimit){
							if(oElm.tagName && oElm.tagName.toLowerCase() == 'td')
								oCell = oElm;//top cell is found
							else if(oElm.tagName && oElm.tagName.toLowerCase() == 'tr'){
								oRow = oElm;
								//bug 6854 break;
							}
							oElm = oElm.parentNode;
						}

						// see if it's a row
						if(oRow && oRow.className.match('selected') && oRow != this.getProperty('suppressedEditRow') && !event.ctrlKey && !event.metaKey && !event.shiftKey){
							if(this.getAttribute('readonly') == 'false')
								this.initEditMode(oCell ? oCell.cellIndex : -1);
							else {
								var sOldIndexes = this.getAttribute('selectedIndexes');
								var sNewIndexes = oRow.getAttribute('rowid');

								this.setAttribute('selectedIndexes', sNewIndexes);
								if(sNewIndexes != sOldIndexes) bb.command.fireEvent(this, 'selectionChanged', false, false);
							}
						}

						// see if it's the column menu
						else{
							var oButton = null;
							var oElm = event.viewTarget;
							var oLimit = this.viewNode;
							while(oElm && oElm != oLimit){
								if(oElm.className && oElm.className.match('btl-grid-topRightFiller')){
									oButton = oElm;
									break;
								}
								oElm = oElm.parentNode;
							}
							if(oButton){
								/*
								@TODO: this is broken because the menu can't be generated dynamically
								var aCoordinates = bb.html.getBoxObject(oButton, 'border');
								//var oMenu = bb.document.getElementById(this.getAttribute('columnmenu'));
								//if(oMenu) oMenu.openMenu(true, aCoordinates[0], aCoordinates[1] + aCoordinates[3]);
								//if(oMenu) oMenu.show(aCoordinates[0], aCoordinates[1] + aCoordinates[3]);
								this.createColumnMenu();
								this._oMenu.show(aCoordinates[0], aCoordinates[1] + aCoordinates[3]);*/
							}
						}
					}
				}
			]]></d:handler>

			<d:handler event="reflow" type="text/javascript"><![CDATA[
				// Show or hide scrollbar filler.
				if( btl.listGrid.hasVScrollBar(this)) bb.html.addClass(this.viewNode, 'btl-grid-scrollbarFillers-hidden');
				else bb.html.removeClass(this.viewNode, 'btl-grid-scrollbarFillers-hidden');

				// Trigger internal reflow in Internet Explorer.
				if(bb.browser.ie && this.viewDataTableContainer.firstChild){
					var oBody = this.viewDataTableContainer.firstChild.tBodies[this.viewDataTableContainer.firstChild.tBodies.length - 1];
					if (oBody.rows.length > 1) {
						oBody.moveRow(0, 1);
						oBody.moveRow(0, 1);
					}
				}
				this.alignColumns();
			]]></d:handler>
		</d:element>

		<d:element name="listGridColBase" extends="b:resize b:dimensionElement b:labelImplementor" abstract="true">
			

			<d:attribute name="align">
				
			</d:attribute>

			<d:attribute name="datatype" default="html">
				
			</d:attribute>

			<d:attribute name="display">
				
				<!-- Initialization of this attribute is handled inside the DOMNodeInsertedIntoDocument event handler -->
				<d:mapper type="text/javascript"><![CDATA[/* override default mapper */]]></d:mapper>
				<d:changer type="text/javascript"><![CDATA[
					if(btl.isTrueValue(name, value) || value == '' || value === undefined){
						this.show();
					} else if (value == 'false' || value == 'none') {
						this.hide();
					} else {
						this.viewNode.style.display = value;
					}
				]]></d:changer>
			</d:attribute>

			<d:attribute name="dataField">
				
				<d:mapper type="text/javascript"><![CDATA[
					this._.select = value;
				]]></d:mapper>
			</d:attribute>

			<d:attribute name="select">
				
				<d:mapper type="text/javascript"><![CDATA[
					this._.select = value;
				]]></d:mapper>
			</d:attribute>

			<d:attribute name="format">
				
			</d:attribute>

			<d:attribute name="editFormat">
				
			</d:attribute>

			<d:attribute name="readonly">
				
			</d:attribute>

			<d:attribute name="width">
				<d:changer type="text/javascript"><![CDATA[
					this.viewNode.style.width = value;
					if(bb.browser.opera) {//Force repaint in Opera (see bug 6123)
						var oParent = this.getProperty('parentNode');
						var currentDisplay = oParent.viewNode.style.display;
						oParent.viewNode.style.display = "none";
						oParent.viewNode.style.display = currentDisplay;
					}
					this.getProperty('parentNode').alignColumns();
				]]></d:changer>
				<d:mapper type="text/javascript"><![CDATA[
					this.viewNode.style.width = value;
				]]></d:mapper>
			</d:attribute>

			<d:property name="dataType">
				
				<d:getter type="text/javascript"><![CDATA[
					var sDataType = this.getAttribute('datatype');
					return sDataType ? sDataType : 'html';
				]]></d:getter>
			</d:property>

			<d:property name="align">
				
				<d:getter type="text/javascript"><![CDATA[
					var sAlign = this.getAttribute('align');
					var sDataType = this.getProperty('dataType');
					if(!sAlign){
						if(sDataType == 'number' || sDataType == 'currency') sAlign = 'right';
						else sAlign = 'left';
					}
					return sAlign;
				]]></d:getter>
			</d:property>

			<d:property name="hidden">
				
			</d:property>

			<d:property name="fieldCreator">
				
				<d:getter type="text/javascript"><![CDATA[
					if( !this._['_'+name])
						btl.listGrid.initFProperties(this)
					return this._['_'+name];
				]]></d:getter>
			</d:property>

			<d:property name="fieldUpdater">
				
				<d:getter type="text/javascript"><![CDATA[
					if( !this._['_'+name])
						btl.listGrid.initFProperties(this);
					return this._['_'+name];
				]]></d:getter>
			</d:property>

			<d:property name="fieldDestroyer">
				
				<d:getter type="text/javascript"><![CDATA[
					if( !this._['_'+name])
						btl.listGrid.initFProperties(this);
					return this._['_'+name];
				]]></d:getter>
			</d:property>

			<d:property name="index">
				
				<d:getter type="text/javascript"><![CDATA[
					var aColumns = this.getProperty('parentNode').getProperty('columns');
					for( var i = 0, iMax = aColumns.length; iMax > i; i++)
						if( aColumns[i] == this)
							return	i;
					return -1;
				]]></d:getter>
			</d:property>

			<d:property name="select">
				
				<d:getter type="text/javascript"><![CDATA[
					if( this._.select)
						return this._.select
					var sFieldName = this.modelNode.getAttribute('dataField');
					var sSelect = this.modelNode.getAttribute('select');
					this._.select = sFieldName && sFieldName.length ? sFieldName :
									 (sSelect && sSelect.length ? sSelect : ('*['+ (this.getProperty('index') + 1) +']'));
					return this._.select;
				]]></d:getter>
			</d:property>

			<d:method name="show">
				
				<d:body type="text/javascript"><![CDATA[
					var iIndex = this.getProperty('index');
					var oParent = this.getProperty('parentNode');
					if( oParent.viewDataTableContainer.firstChild){
						var aRows = oParent.viewDataTableContainer.firstChild.rows;
						for(var i = aRows.length - 1; i >= 0; i--){
							aRows[i].cells[iIndex].style.display = '';
						}
					}
					this.viewNode.style.display = '';
					this.setProperty('hidden', false);
					oParent.alignColumns();
					oParent.setColumnResizing('true');
				]]></d:body>
			</d:method>

			<d:method name="hide">
				
				<d:argument name="skipalign">
					
				</d:argument>
				<d:body type="text/javascript"><![CDATA[
					var iIndex = this.getProperty('index');
					var oParent = this.getProperty('parentNode');
					if( oParent.viewDataTableContainer.firstChild){
						var aRows = oParent.viewDataTableContainer.firstChild.rows;
						for(var i = aRows.length - 1; i >= 0; i--){
							aRows[i].cells[iIndex].style.display = 'none';
						}
					}
					this.viewNode.style.display = 'none';
					this.setProperty('hidden', true);
					if(!skipalign) oParent.alignColumns();
					oParent.setColumnResizing('true');
				]]></d:body>
			</d:method>

			<d:handler event="resizeStart" type="text/javascript"><![CDATA[
				// Store initial values.
				if(event.resizeEdges.match('right')){
					var aCoordinates = bb.html.getBoxObject(this.viewNode);
					this.resizedHead = this;
					this.resizeOriginalW = aCoordinates.width;
				}
				else if(event.resizeEdges.match('left')){
					var oResizedHead;
					var oModelNode = this.modelNode;
					while(oModelNode.previousSibling){
						oModelNode = oModelNode.previousSibling;
						if(oModelNode.nodeType == 1 && bb.instanceOf(bb.getControllerFromModel(oModelNode), btl.namespaceURI, 'listGridColBase') && !bb.getControllerFromModel(oModelNode).getProperty('hidden')){
							oResizedHead = bb.getControllerFromModel(oModelNode);
							break;
						}
					}
					this.resizedHead = oResizedHead;

					var aCoordinates = bb.html.getBoxObject(oResizedHead.viewNode);
					this.resizeOriginalW = aCoordinates.width;
				}

				// Append resize line to the grid.
				var oParent = this.getProperty('parentNode');
				var oMain = oParent.viewDataTableContainer;
				oParent.viewNode.appendChild(btl.resize.lineElement);

				// Adjust height of the resize line.
				var iScrollAdjust = btl.listGrid.hasHScrollBar( oParent) ? bb.html.getScrollBarWidth() : 0;
				btl.resize.lineElement.style.height = oParent.viewNode.offsetHeight - iScrollAdjust + 'px';
				btl.resize.lineElement.style.borderStyle = 'none solid none none';

				// Adjust position of the resize line.
				btl.resize.lineElement.style.left = this.resizedHead.viewNode.offsetLeft + this.resizedHead.viewNode.offsetWidth - oMain.scrollLeft + 'px';
				btl.resize.lineElement.style.top = '0px';
			]]></d:handler>

			<d:handler event="resize" type="text/javascript"><![CDATA[
				// Position resize line.
				var iNewW = bb.html.getBoxObject(this.resizedHead.viewNode).width + event.deltaX;
				if(iNewW < 10) iNewW = 10;
				var iNewX = this.resizedHead.viewNode.offsetLeft + iNewW;
				var oParent = this.getProperty('parentNode');
				var oMain = oParent.viewDataTableContainer;
				iNewX -= oMain.scrollLeft;
				if(iNewX > oMain.clientWidth) iNewX -= 10000;
				btl.resize.lineElement.style.left = iNewX + 'px';
			]]></d:handler>

			<d:handler event="resizeEnd" type="text/javascript"><![CDATA[
				// Update width of column in the end.
				if(event.resizeEdges.match('right') || event.resizeEdges.match('left')) {
					var iNewW = this.resizeOriginalW + event.deltaX;
					if(iNewW < 10) iNewW = 10;
					this.resizedHead.setAttribute('width', iNewW + 'px');
				}
				// Cleanup
				document.body.appendChild(btl.resize.lineElement);
				this.resizedHead = null;
			]]></d:handler>

			<d:handler event="click" type="text/javascript"><![CDATA[
				// @NOTE: fieldEditor element is nested inside the listGridCol making
				// all events from the editor control to bubble up to the listGridCol,
				// still the view structure is different and if HTML element is inside
				// the listGridCol view node - it is definately does not belong to editor.
				// This logic is used here to proceed only "real" listGridCol click.
				if(btl.containsElement(this.viewNode, event.viewTarget) || this.viewNode == event.viewTarget){
					var oParent = this.getProperty('parentNode');
					var sSortable = oParent.getAttribute('sortable') || 'true';
					if(event.button == 0 && sSortable == 'true') {
						var iColumn = this.viewNode.cellIndex;
						if(bb.browser.ie) {
							var i = iHiddenCols = 0, oCells = this.viewNode.parentNode.getElementsByTagName("th");
							while(oCells[i] != this.viewNode) {
								if(oCells[i++].style.display == "none")
									iHiddenCols++;
							}
							iColumn += iHiddenCols;
						}
						//if the grid is sorted on this column or the current sort direction is not default
						var bReverse = (oParent.getProperty('sorted') && (oParent.getProperty('sortField') == this._.select))
						 || (oParent.getProperty('sortDirection') != 'ascending');

						oParent.sortColumn(iColumn, bReverse);
					}
				}
			]]></d:handler>

			<d:handler event="construct" type="text/javascript"><![CDATA[
				/* This DOMNodeInsertedIntoDocument event handler takes care of correctly mapping the display property during initialization */
				var sFieldName = this.modelNode.getAttribute('dataField');
				var sSelect = this.modelNode.getAttribute('select');
				if( sFieldName && sSelect && sSelect.length && sFieldName.length)
			 		bb.command.trace( this, "'fieldName' and 'select' attributes('"+sFieldName+"', '"+sSelect+"') must not be defined simultaneously", 3);
			]]></d:handler>

			<d:handler event="DOMNodeInsertedIntoDocument" type="text/javascript"><![CDATA[
				var sValue = this.getAttribute('display');
				if(sValue == 'false' || sValue == 'none')
					this.hide();
				else
					this.setProperty('hidden', false)
			]]></d:handler>
		</d:element>

		<!-- d:element name="fieldEditor">
			<bda:documentation>
				<bda:summary>
					<p>
						Used to define the content of a &listgrid; cell when it is
						edited. For example, you can add a select control in the editor with
						predefined options, which will be displayed when the specific cell is edited.
					</p>
					<p>
						The &fieldeditor; is a child widget of a &listgrid; or &treegrid; column
						that can be used when you do not want to use the default input type (a standard input field)
						or you want to change the attributes of this widget.
						Any form widget that accepts a value
						can be inserted as a child of the &fieldeditor; widget.
					</p>
					<img src="screen_editor.jpg" alt="BTL editor" title="BTL editor" />
				</bda:summary>
				<bda:parenttags>
					<b:listGridCol />
					<b:treeGridCol />
				</bda:parenttags>
				<bda:examples>
					<exp:example ref="btl:btl_editor" />
				</bda:examples>
			</bda:documentation>
			<d:template type="application/xhtml+xml"><div class="btl-editor"><d:content /></div></d:template>
			<d:resource type="text/css">
				.btl-editor {
					display: none;
				}
			</d:resource>
		</d:element -->

		<d:element name="fieldCreator">
			

			<d:method name="__children">
				
				<d:body type="text/javascript"/>
			</d:method>

			<d:constructor type="text/javascript"><![CDATA[
				var sText = this.getProperty('textContent');
				this._._body = new Function ("viewNode", "controller", "recordId", "value", sText);
			]]></d:constructor>
		</d:element>

		<d:element name="fieldUpdater">
			

			<d:method name="__children">
				
				<d:body type="text/javascript"/>
			</d:method>

			<d:constructor type="text/javascript"><![CDATA[
				var sText = this.getProperty('textContent');
				this._._body = new Function ("viewNode", "controller", "object", "recordId", "value", sText);
			]]></d:constructor>
		</d:element>

		<d:element name="fieldDestroyer">
			

			<d:method name="__children">
				
				<d:body type="text/javascript"/>
			</d:method>

			<d:constructor type="text/javascript"><![CDATA[
				var sText = this.getProperty('textContent');
				this._._body = new Function ("object", "recordId", sText);
			]]></d:constructor>
		</d:element>
	</d:namespace>
</d:tdl>